package tuding.android.bigplanettracks.maps;

import tuding.android.bigplanettracks.maps.loader.TileLoader;
import tuding.android.bigplanettracks.maps.providers.MapStrategy;
import tuding.android.bigplanettracks.maps.providers.MapStrategyFactory;
import tuding.android.bigplanettracks.maps.storage.BitmapCacheWrapper;
import tuding.android.bigplanettracks.maps.storage.LocalStorageWrapper;
import tuding.android.bigplanettracks.maps.ui.MapControl;
import android.util.Log;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class TileResolver {

	private TileLoader tileLoader;

	private PhysicMap physicMap;

	private BitmapCacheWrapper cacheProvider = BitmapCacheWrapper.getInstance();

	protected Handler scaledHandler;

	private Handler localLoaderHandler;

	private int strategyId = -1;

	private static int loaded = 0;

	public TileResolver(final PhysicMap physicMap) {
		this.physicMap = physicMap;
		tileLoader = new TileLoader(
		// обработчик загрузки тайла с сервера
				new Handler() {
					@Override
					public void handle(RawTile tile, byte[] data) {
						LocalStorageWrapper.put(tile, data);
						Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
						cacheProvider.putToCache(tile, bmp);
			        	// remove the tile fetching from Internet
						if(!TileLoader.loadingQueue.remove(tile)) {
			        		//Log.e("LOADER", "loadingQueue does not contain the removing tile: "+tile.x+" "+tile.y);
			        	}
						//Log.i("UPDATEMAP", "loadingQueue is removing tile: "+tile.x+" "+tile.y);
						updateMap(tile, bmp);
					}
				});
		//new Thread(tileLoader, "TileLoader").start();

		// обработчик загрузки скалированых картинок
		this.scaledHandler = new Handler() {

			@Override
			public synchronized void handle(RawTile tile, Bitmap bitmap,
					boolean isScaled) {
				loaded++;
				if (bitmap != null) {
					if (isScaled) {
						cacheProvider.putToScaledCache(tile, bitmap);
						updateMap(tile, bitmap);
					}
				}
			}

		};
		// обработчик загрузки с дискового кеша
		this.localLoaderHandler = new Handler() {

			@Override
			public void handle(RawTile tile, Bitmap bitmap, boolean isScaled) {
				//Log.i("LocalLoaderHandle", "HERE");
				if (tile.s == -1) {
					throw new IllegalStateException();
				}
				if (bitmap != null) { // если тайл есть в файловом кеше
					cacheProvider.putToCache(tile, bitmap); // this call may block the routine, so we need loaded be inc later
					//Log.i("ZOOM","loaded inc in localLoaderHandler, from storage");
					loaded++;
					updateMap(tile, bitmap);
				} else { // если тайла нет в файловом кеше
					loaded++;
					//Log.i("ZOOM","need load from Internet");
					updateMap(tile, MapControl.CELL_BACKGROUND);
					load(tile);
				}
			}

		};

	}

	/**
	 * Добавляет в очередь на загрузку с сервера
	 * 
	 * @param tile
	 */
	private void load(RawTile tile) { 
		if (tile.s != -1 && tile.z == PhysicMap.getZoomLevel() ) {
			// we only load those tile for current view
		    //if( tile.x >= physicMap.getDefaultTile().x && tile.x <= (physicMap.getDefaultTile().x+physicMap.cells.length)
		    // && tile.y >= physicMap.getDefaultTile().y && tile.y <= (physicMap.getDefaultTile().y+physicMap.cells[0].length)) {
		    	//Log.i("TR","tile: "+tile.x+" "+tile.y+" "+tile.z);
			    tileLoader.load(tile);
		    //}
		}
	}

	public void updateMap(RawTile tile, Bitmap bitmap) {
		//Log.i("PMAP", "tile.s : "+tile.s+" strategyId "+strategyId);
		if (tile.s == strategyId) {
			//Log.i("UPDATEMAP","Call pmap update from TileResolver!");
			physicMap.update(bitmap, tile);
		}
	}

	
	public Bitmap loadTile(final RawTile tile){
		return cacheProvider.getTile(tile);
	}
	
	/**
	 * Загружает заданный тайл
	 * 
	 * @param tile
	 * @return
	 */
	public void getTile(final RawTile tile) {
		if (tile.s == -1) {
			return;
		}
		Bitmap bitmap = cacheProvider.getTile(tile);
		if (bitmap != null) {
			loaded++;
			//Log.w("UPDATEMAP","-->cacheProvider  contain tile:"+tile.x+" "+tile.y);
			updateMap(tile, bitmap);
		} else {
			loaded++;
			bitmap = LocalStorageWrapper.get(tile);
			if (bitmap != null) {
				updateMap(tile, bitmap);
				cacheProvider.putToCache(tile, bitmap); 
			} else {
				updateMap(tile, MapControl.CELL_BACKGROUND);
				LocalStorageWrapper.get(tile, localLoaderHandler);
			}
			Log.w("UPDATEMAP","cacheProvider doesnot contain tile:"+tile.x+" "+tile.y);

//			if(TileLoader.loadingQueue.contains(tile)) {
//				loaded++;
//				updateMap(tile, MapControl.CELL_BACKGROUND);
//			} else {
//				//Log.i("UPDATEMAP","getTile: "+tile.x+" "+tile.y+" "+tile.z);
//			    LocalStorageWrapper.get(tile, localLoaderHandler);
//			}
		}
	}

	public synchronized void setMapSource(int sourceId) {
		clearCache();
		MapStrategy mapStrategy = MapStrategyFactory.getStrategy(sourceId);
		this.strategyId = sourceId;
		tileLoader.setMapStrategy(mapStrategy);
	}

	public void clearCache() {
		cacheProvider.clear();
	}

	public int getMapSourceId() {
		return this.strategyId;
	}

	public void setUseNet(boolean useNet) {
		tileLoader.setUseNet(useNet);
		if (useNet) {
			physicMap.reloadTiles();
		}
	}
	
	public Bitmap[][] fillMap(RawTile tile, final int size){
		Bitmap[][] cells = new Bitmap[size][size];
		for(int i=0;i<size;i++){
			for(int j=0;j<size;j++){
				int x, y;
				x = (tile.x + i);
				y = (tile.y + j);
				
				RawTile tmp = new RawTile(x,y,tile.z, tile.s);
				
				Bitmap bitmap;
				bitmap =  cacheProvider.getTile(tmp);
				if(bitmap==null){
					bitmap= LocalStorageWrapper.get(tmp);
					if(bitmap==null){
						bitmap = TileScaler.get(tmp);
						if(bitmap==null){
							// установить фон
						}
					}
				}
				cells[i][j]=bitmap;
			}
		}
		return cells;
	}

	public static synchronized void incLoaded(){
		loaded++;
//		System.out.println("inc " + this.loaded);
	}

	
	public synchronized int getLoaded(){
//		System.out.println("getLoaded " + this.loaded);
		return loaded;
	}
	
	public synchronized void resetLoaded(){
//		System.out.println("inc " + this.loaded);
		loaded = 0;
	}
}
